package com.straw.hat.shardingjdbc.config;

import com.alibaba.druid.pool.DruidDataSource;
import io.shardingsphere.api.config.rule.ShardingRuleConfiguration;
import io.shardingsphere.api.config.rule.TableRuleConfiguration;
import io.shardingsphere.api.config.strategy.InlineShardingStrategyConfiguration;
import io.shardingsphere.core.keygen.DefaultKeyGenerator;
import io.shardingsphere.core.keygen.KeyGenerator;
import io.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.support.TransactionTemplate;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @company: 鲸灵科技
 * @author: qiyue@webuy.ai
 * @date: 2019/10/7
 * @time: 12:37 上午
 */
@Configuration
@EnableTransactionManagement // 开启注解事务管理，等同于xml配置文件中的 <tx:annotation-driven />
public class DataSourceConfig {


    private List<String> urls;
    @Value("${shardingjdbc.driver}")
    private String drive;
    @Value("${shardingjdbc.username}")
    private String username;
    @Value("${shardingjdbc.password}")
    private String password;
    @Value("${shardingjdbc.max}")
    private Integer max = 50;
    @Value("${shardingjdbc.min}")
    private Integer min = 1;
    @Value("${shardingjdbc.testWhileIdle}")
    private Boolean testWhileIdle;
    @Value("${shardingjdbc.transaction.timeout}")
    private Integer timeout;

    private String validationQuery = "select 1";
    private String filters ="stat";

    @Bean
    @Primary
    public DataSource dataSource() throws SQLException {
        if (!Optional.ofNullable(urls).isPresent() || urls.size() <= 0) {
            urls=new ArrayList<>();
            urls.add("jdbc:mysql://192.168.0.105:3310/iproduce_biz_0?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC");
            urls.add("jdbc:mysql://192.168.0.105:3309/iproduce_biz_1?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC");
        }

        AtomicInteger count = new AtomicInteger(0);

        /*多数据源配置*/
        Map<String, DataSource> daatasourceMap = urls.parallelStream().collect(Collectors.toMap(url -> buildName(count.getAndIncrement()), url -> createDatasource(url)));

        /*逻辑库表和真实库表配置*/
        TableRuleConfiguration tableRule =new TableRuleConfiguration();

        tableRule.setLogicTable("straw_user_info");

        tableRule.setActualDataNodes("datasource_${0..1}.straw_user_info_${0..1}");

        tableRule.setKeyGeneratorColumnName("id");

        tableRule.setKeyGenerator(new DefaultKeyGenerator());

        /*配置分库 + 分表策略*/

        tableRule.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("city","datasource_${city % 2}"));

        tableRule.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("id","straw_user_info_${id % 2}"));


        // 配置分片规则

        ShardingRuleConfiguration shardingRuleConfig =new ShardingRuleConfiguration();

        shardingRuleConfig.getTableRuleConfigs().add(tableRule);

        // 获取数据源对象
        Properties props = new Properties();
        props.put("sql.show", true);
        return ShardingDataSourceFactory.createDataSource(daatasourceMap, shardingRuleConfig,new ConcurrentHashMap(), props);
    }


    private String buildName(Integer count){
        return "datasource_"  + count;
    }


    private DataSource createDatasource(String url)  {
        DruidDataSource dataSource = null;
        try {
            dataSource = new DruidDataSource();
            dataSource.setUrl(url);
            dataSource.setDriverClassName(drive);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            dataSource.setMaxActive(max);
            dataSource.setMinIdle(min);
            dataSource.setValidationQuery(validationQuery);
            dataSource.setTestWhileIdle(testWhileIdle);
            dataSource.setFilters(filters);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataSource;


    }
    /**事务管理器控制事务的开启提交回滚操作*/
    @Bean
    public PlatformTransactionManager platformTransactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }

    /**设置事务的特性的模板*/
    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager platformTransactionManager){
        TransactionTemplate transactionTemplate = new TransactionTemplate();
        transactionTemplate.setTransactionManager(platformTransactionManager);
        transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        transactionTemplate.setTimeout(timeout);
        return transactionTemplate;
    }


}
